#include "EventLoop.h"
#include <unistd.h>
#include "Acceptor.h"
#include "TcpConnection.h"
#include <iostream>

EventLoop::EventLoop(Acceptor & acceptor)
:_epfd(createEpollFd())
,_evtList(1024)
,_isLooping(false)
,_acceptor(acceptor)
{
    int listenfd = _acceptor.fd();
    addEpollReadFd(listenfd);
}

EventLoop::~EventLoop(){
    close(_epfd);
}

void EventLoop::loop(){
    _isLooping = true;
    while(_isLooping){
        waitEpollFd();
    }
}
void EventLoop::unloop(){
    _isLooping = false;
}

void EventLoop::waitEpollFd(){
    int nready = 0;
    do{
        nready = epoll_wait(_epfd,&*_evtList.begin(),_evtList.size(),3000);

    }while(-1 == nready && errno == EINTR);

    if(-1 == nready){
        cout << "nready == -1" << endl;
        return;
    }else if(nready == 0){
        cout << ">>epoll_wait timeout!!!" << endl;
    }else{
        if((int)_evtList.size() == nready){
            _evtList.resize(2 * nready);
        }

        for(int idx = 0;idx < nready; ++idx){
            int listenfd = _acceptor.fd();
            int fd = _evtList[idx].data.fd;
            if(listenfd == fd)
            {
                handleNewConnection();
            }
            else
            {
                handleMessage(fd);
            }
        }
    }
}

void EventLoop::handleNewConnection(){
    int connfd = _acceptor.accept();
    if(connfd < 0){
        perror("handleNewConnection");
        return;
    }
    addEpollReadFd(connfd);
    TcpConnectionPtr con(new TcpConnection(connfd));

    _conns[connfd] = con;

}

void EventLoop::handleMessage(int fd){
    auto it = _conns.find(fd);
    if(it != _conns.end()){
        string msg = it->second->receive();
        cout << ">>receive msg from client: " << msg << endl;
        it->second->send(msg);
    }else{
        cout << "该连接不存在" << endl;
        return;
    }

}

int EventLoop::createEpollFd(){
    int fd = epoll_create1(0);
    if(fd < 0){
        perror("createEpollFd");
        return fd;
    }
    return fd;
}

void EventLoop::addEpollReadFd(int fd){
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;

    int ret = epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&evt);
    if(ret < 0){
        perror("epoll_ctl add");
        return;
    }
}

void EventLoop::delEpollReadFd(int fd){
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;
    int ret = epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,&evt);
    if(ret < 0){
        perror("epoll_ctl del");
        return;
    }

}
